/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CardGame;

import Service.CardConstant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Nhan Nguyen
 */
public class GameTable {

    public static Logger log = LoggerFactory.getLogger(GameTable.class.getName());
    public String tableID;
    private int maxOfUsers;
    public int tableStatus;
    public int betMoney;
    public int betMoneyDefault;
    public int tableType;
    public byte winType;
    //public String tableMaster;
    public ArrayList playerList = null; // danh sach nguoi choi vao ban - xoa neu thoat
    public List playerJoined = null; // danh sach nguoi choi tham gia van bai - ko xoa neu thoat
    public ArrayList playerCongBai = null;
    public ArrayList playerThoatNgang = null;
    public ArrayList playerMatLuotDoQuaGio = null;
    public String[] playerResult; // xep thu tu nguoi choi vao cuoi van
    public Integer[] playerBalance; // so tien +/- cua tung user so voi playerJoined
    public boolean isPlaying = false; // ban co dang choi hay ko
    public boolean isFirstDeal = false; // chia bai lan dau tien khi vua vao/toi trang
    //public String FirstHand;
    public byte[][] cards = null;
    public byte[] noCardsLeft = null; // so la bai con lai - tuong ung voi playerJoined
    public byte[] lastPlayedCards = null; // danh sach la bai vua danh
    public byte lastMoveType = CardConstant.MOVE_INVALID;
    public boolean isNewTurn = false; // luot moi
    //public boolean isFinished = false;
    public boolean isPlayerChanged = false; // thay doi nguoi choi
    public byte nextTurnPlayer = -1; // nguoi choi ke tiep trong luot
    public byte lastTurnPlayer = -1; // nguoi vua danh
    public boolean[] playerBypassedTurn; // player mat luot choi
    public boolean[] playerWithTurnPriority; // player co do choi (4 doi thong...?)
    public boolean isHuongSaiTurn = false;
    public Timer timeoutTimer;
    public long startTime;
    public String lastWinner = null;
    public String password = null;  // hanv
    public String nguoiBiChat = null;
    public String nguoiChat = null;
    public int soTienChat = 0;
    public boolean isTruTienBatCong = false;
    public ArrayList chatChongList = new ArrayList();
    //public byte chatChongIndex=0;
    public byte[][] ungHangList = new byte[4][6];
//    private ArrayList effectList = null;
    public int game_id = 0;
    public int game_date = 0;

    public GameTable() {
        playerList = new ArrayList();
        playerJoined = Collections.synchronizedList(new ArrayList());
        //playerResult = new HashMap<String,Integer>();
        playerResult = new String[4];
        playerBalance = new Integer[4];
        playerThoatNgang = new ArrayList();
//        effectList = new ArrayList();
        cards = new byte[4][13];
        noCardsLeft = new byte[4];
        playerBypassedTurn = new boolean[4];
        playerWithTurnPriority = new boolean[4];
        playerCongBai = new ArrayList();
        playerMatLuotDoQuaGio = new ArrayList();
        chatChongList = new ArrayList();
        //chatChongIndex=0;
        isTruTienBatCong = false;
        ungHangList = new byte[4][6];
        // initialize card set
        int index = 0;
        for (int number = 3; number <= 15; number++) {
            for (int suit = 0; suit < 4; suit++) {
                cards[index / 13][index % 13] = (byte) (number * 4 + suit);
                index++;
            }
        }
    }

    public void resetUngHangList() {
        for (int i = 0; i < playerJoined.size(); i++) {
            for (int j = 0; j < 6; j++) {
                ungHangList[i][j] = 0;
            }
        }
    }

    public int getNumberOfJoinedPlayers() {
        return playerJoined.size();
    }

    public int getNumberOfPlayers() {
        //if (playerList.size()>0) log.info("TableID: "+tableID+" has "+playerList.size()+" user(s)");
        return playerList.size();
    }

    public int getMaxPlayers() {
        return maxOfUsers;
    }

    public void setMaxPlayers(int maxUser) {
        if (maxUser >= getNumberOfPlayers()) {
            maxOfUsers = maxUser;
        }
    }

    public void dealCards(int test) {
        byte cardTest0[][] = {
            {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24},
            {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37},
            {38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50},
            {51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}};

        // tu quy 3
        byte cardTest1[][] = {
            {12, 13, 14, 15, 24, 27, 25, 44, 49, 53, 56, 58, 59},
            {20, 19, 28, 33, 35, 37, 38, 42, 46, 50, 51, 62, 63},
            {17, 16, 21, 23, 31, 30, 32, 39, 43, 45, 52, 60, 61},
            {18, 22, 26, 29, 34, 36, 40, 41, 47, 54, 55, 57, 48}};

        // 4 đôi thông
        byte cardTest2[][] = {
            {17, 18, 22, 23, 24, 26, 28, 30, 12, 47, 52, 48, 59},
            {15, 25, 16, 27, 31, 38, 41, 45, 57, 55, 56, 60, 62},
            {34, 19, 33, 29, 37, 35, 42, 49, 50, 51, 53, 54, 61},
            {39, 13, 14, 20, 21, 32, 36, 40, 43, 44, 46, 58, 63}};

        // tu quy 5
        byte cardTest3[][] = {
            {12, 20, 21, 22, 23, 32, 36, 44, 49, 55, 40, 59, 63},
            {14, 28, 25, 19, 60, 33, 35, 37, 38, 42, 43, 61, 62},
            {18, 24, 15, 17, 30, 27, 39, 46, 45, 48, 53, 56, 57},
            {52, 13, 26, 29, 34, 16, 58, 41, 47, 54, 31, 50, 51}
        };

        // 3 doi thong + 3 bich
        byte cardTest4[][] = {
            {12, 13, 16, 17, 20, 21, 14, 19, 28, 33, 35, 37, 38, 42},
            {46, 42, 22, 23, 24, 27, 31, 44, 49, 53, 55, 58, 63},
            {59, 18, 51, 15, 25, 30, 32, 39, 43, 45, 48, 56, 57},
            {52, 50, 26, 29, 34, 36, 40, 41, 47, 54, 60, 61, 62}
        };

        // 3 doi thong
        byte cardTest5[][] = {
            {12, 53, 37, 39, 41, 43, 45, 46, 63, 54, 55, 52, 59},
            {19, 24, 29, 30, 31, 32, 33, 36, 38, 44, 48, 49, 62},
            {14, 15, 17, 18, 20, 22, 28, 40, 42, 60, 25, 58, 61},
            {13, 16, 21, 23, 26, 27, 34, 35, 47, 51, 57, 56, 50}};

        // 5 doi thong
        byte cardTest6[][] = {
            {14, 37, 39, 41, 43, 45, 46, 49, 50, 54, 55, 58, 60},
            {13, 16, 17, 24, 28, 32, 33, 52, 53, 56, 57, 59, 61},
            {19, 18, 25, 29, 30, 31, 20, 22, 36, 38, 44, 48, 63},
            {12, 15, 21, 23, 26, 27, 34, 35, 47, 51, 40, 62, 42}};

        // 6 doi - tu quy 9
        byte cardTest7[][] = {
            {14, 15, 19, 20, 21, 24, 25, 28, 29, 36, 37, 38, 39},
            {17, 42, 40, 30, 31, 32, 33, 52, 58, 44, 48, 49, 56},
            {13, 22, 41, 43, 45, 46, 50, 54, 55, 57, 59, 60, 61},
            {12, 16, 18, 23, 26, 27, 34, 35, 47, 51, 53, 62, 63}};

        // sanh lien tuc
        byte cardTest8[][] = {
            {12, 13, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60},
            {14, 15, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61},
            {16, 17, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62},
            {18, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63}};

        byte cardTest9[][] = {
            {16, 17, 14, 19, 28, 33, 35, 37, 42, 60, 61, 62, 63},
            {20, 21, 52, 13, 24, 27, 31, 44, 49, 53, 55, 58, 59},
            {18, 12, 15, 25, 30, 32, 38, 39, 46, 45, 48, 56, 57},
            {22, 23, 26, 29, 34, 36, 40, 41, 43, 47, 54, 50, 51}};

        lastTurnPlayer = -1;
        lastPlayedCards = null;
        nextTurnPlayer = -1;
        isNewTurn = true;
        //isFinished=false;
        //playerInitializedTurn=0;

//        isPlaying = true;
        winType = 0;

        java.util.Arrays.fill(playerResult, null);
        java.util.Arrays.fill(playerBalance, -betMoney);

        java.util.Arrays.fill(noCardsLeft, (byte) 0);
        java.util.Arrays.fill(playerBypassedTurn, false);
        java.util.Arrays.fill(playerWithTurnPriority, false);

//        effectList = new ArrayList();
//        for (int i = 0; i < playerJoined.size(); i++) {
//            String currPlayer = (String) playerJoined.get(i);
//
//            SpecialEffect effect = SpecialEffectManager.checkSpecialEffect(currPlayer, EffectType.X2_BET);
//            if (effect != null) {
//                effectList.add(effect);
//            }
//            effect = SpecialEffectManager.checkSpecialEffect(currPlayer, EffectType.X2_CHAT_HEO);
//            if (effect != null) {
//                effectList.add(effect);
//            }
//            effect = SpecialEffectManager.checkSpecialEffect(currPlayer, EffectType.X2_THUI_BAI);
//            if (effect != null) {
//                effectList.add(effect);
//            }
//        }

        // reset card order
        for (int i = 0; i < 52; i++) {
            cards[i / 13][i % 13] = (byte) (i + 12);
        }

        Random rgen = new Random();  // Random number generator
        //--- Shuffle by exchanging each element randomly
        for (int i = 0; i < 52; i++) {
            int pos = rgen.nextInt(52);
            byte temp = cards[i / 13][i % 13];
            cards[i / 13][i % 13] = cards[pos / 13][pos % 13];
            cards[pos / 13][pos % 13] = temp;
        }

        /**
         * Hard code la bai
         */
        if (test > 0) {
            byte cardTest[][] = null;
            switch (test) {
                case 1:
                    cardTest = cardTest1;
                    break;
                case 2:
                    cardTest = cardTest2;
                    break;
                case 3:
                    cardTest = cardTest3;
                    break;
                case 4:
                    cardTest = cardTest4;
                    break;
                case 5:
                    cardTest = cardTest5;
                    break;
                case 6:
                    cardTest = cardTest6;
                    break;
                case 7:
                    cardTest = cardTest7;
                    break;
                case 8:
                    cardTest = cardTest8;
                    break;
                case 9:
                    // cardTest = cardTest9;
                    for (int i = 1; i < 4; i++) {
                        for (int j = 0; j < 13; j++) {
                            if (cards[i][j] >= 60) {
                                for (int k = 0; k < 13; k++) {
                                    if (cards[0][k] < 60) {
                                        byte temp = cards[0][k];
                                        cards[0][k] = cards[i][j];
                                        cards[i][j] = temp;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    break;

                case 10:
                case 11:
                    int[] sum = new int[]{0, 0, 0, 0};
                    int max1 = 0;
                    int max2 = 0;
                    int i1 = -1;
                    int i2 = -1;

                    for (int i = 0; i < 4; i++) {
                        for (int j = 0; j < 13; j++) {
                            if (cards[i][j] >= 40) {
                                sum[i] += cards[i][j];
                            } else if (cards[i][j] <= 24) {
                                sum[i] -= cards[i][j];
                            }
                        }
                        // log.debug("sum{} {}", i, sum[i]);
                        if (sum[i] > max1) {
                            max1 = sum[i];
                            i1 = i;
                        }
                    }

                    if (i1 != 0) {
                        // log.debug("max1 {}", max1);
                        byte[] tmp = cards[0];
                        cards[0] = cards[i1];
                        cards[i1] = tmp;
                    }

                    for (int i = 1; i < 4; i++) {
                        sum[i] = 0;
                        for (int j = 0; j < 13; j++) {
                            if (cards[i][j] >= 40) {
                                sum[i] += cards[i][j];
                            } else if (cards[i][j] <= 24) {
                                sum[i] -= cards[i][j];
                            }
                        }

                        if (sum[i] > max2 && sum[i] < max1) {
                            max2 = sum[i];
                            i2 = i;
                        }
                    }

                    if (i2 != 3 && i2 != -1) {
                        // log.debug("max2 {}", max2);
                        byte[] tmp = cards[3];
                        cards[3] = cards[i2];
                        cards[i2] = tmp;
                    }

                    if (getNumberOfJoinedPlayers() >= 3) {
                        for (int i = 0; i < 4; i++) {
                            java.util.Arrays.sort(cards[i]);
                        }

                        if (cards[1][0] == 12) {
                            cards[1][0] = cards[0][0];
                            cards[0][0] = 12;
                        } else if (cards[2][0] == 12) {
                            cards[2][0] = cards[3][0];
                            cards[3][0] = 12;
                        }

                        if (test == 11) {
                            for (int i=12; ; i--) {
                                if (cards[3][i] < 60) {
                                    cards[0][1] = cards[3][i];
                                    byte temp = cards[0][0];
                                    if (cards[0][0] != 12) {
                                        cards[0][0] = cards[3][i-1];
                                    } else {
                                        temp = cards[0][2];
                                        cards[0][2] = cards[3][i-1];
                                    }
                                    cards[3][i-1] = temp;
                                    break;
                                }
                            }
                        }
                    }
                    break;

                case 12:
                    sum = new int[]{0, 0, 0, 0};
                    int min = 0;
                    int minid = 0;

                    for (int i = 0; i < 4; i++) {
                        for (int j = 0; j < 13; j++) {
                            if (cards[i][j] >= 40) {
                                sum[i] += cards[i][j];
                            } else if (cards[i][j] <= 24) {
                                sum[i] -= cards[i][j];
                            }
                        }

                        if (i == 0) {
                            min = sum[i];
                        } else if (sum[i] < min) {
                            min = sum[i];
                            minid = i;
                        }
                    }

                    if (minid != 0) {
                        // log.debug("max1 {}", max1);
                        byte[] tmp = cards[0];
                        cards[0] = cards[minid];
                        cards[minid] = tmp;
                    }

                    break;

//                case 12:
//                    sum = new int[]{0, 0, 0, 0};
//                    max1 = 0;
//                    max2 = 0;
//                    i1 = -1;
//                    i2 = -1;
//
//                    for (int i = 0; i < 4; i++) {
//                        for (int j = 0; j < 13; j++) {
//                            if (cards[i][j] >= 40) {
//                                sum[i] += cards[i][j];
//                            } else if (cards[i][j] <= 24) {
//                                sum[i] -= cards[i][j];
//                            }
//                        }
//                        // log.debug("sum{} {}", i, sum[i]);
//                        if (sum[i] > max1) {
//                            max1 = sum[i];
//                            i1 = i;
//                        }
//                    }
//
//                    if (i1 != 0) {
//                        // log.debug("max1 {}", max1);
//                        byte[] tmp = cards[0];
//                        cards[0] = cards[i1];
//                        cards[i1] = tmp;
//                    }
//
//                    for (int i = 1; i < 4; i++) {
//                        sum[i] = 0;
//                        for (int j = 0; j < 13; j++) {
//                            if (cards[i][j] >= 40) {
//                                sum[i] += cards[i][j];
//                            } else if (cards[i][j] <= 24) {
//                                sum[i] -= cards[i][j];
//                            }
//                        }
//
//                        if (sum[i] > max2 && sum[i] < max1) {
//                            max2 = sum[i];
//                            i2 = i;
//                        }
//                    }
//
//                    if (i2 != 3 && i2 != -1) {
//                        // log.debug("max2 {}", max2);
//                        byte[] tmp = cards[3];
//                        cards[3] = cards[i2];
//                        cards[i2] = tmp;
//                    }
//                    break;
            }

            if (cardTest != null) {
                for (int i = 0; i < 4; i++) {
                    for (int j = 0; j < 13; j++) {
                        cards[i][j] = cardTest[i][j];
                    }
                }
            }
        }

        for (int i = 0; i < 4; i++) {
            java.util.Arrays.sort(cards[i]);
        }
    }

    public String getNextPlayer(String curPlayer) {
        TienLenService.logGame.debug("Cur Player " + curPlayer);
        int playerIndex = playerJoined.indexOf(curPlayer);
        TienLenService.logGame.debug("Cur index " + playerIndex);
        if (playerIndex == -1) {
            return null;
        }
        playerIndex = (playerIndex + 1) % playerJoined.size();
        return (String) playerJoined.get(playerIndex);
    }

    public String getFirstPlayer() {

        TienLenService.logGame.debug("Last Winner " + lastWinner);
        if ((lastWinner != null) && (playerJoined.indexOf(lastWinner) != -1)) {
            return lastWinner;
        }

        // ai co quan bai nho nhat di truoc
        byte minPlayer = 0, minValue = 100;

        int i = 0, size = getNumberOfJoinedPlayers();
        try {
            for (i = 0; i < size; i++) {
                if (minValue > cards[i][0]) {
                    minValue = cards[i][0];
                    minPlayer = (byte) i;
                }
            }
        } catch (Exception ex) {
            log.error(tableID + ": Finding first player at " + i + "/" + size, ex);
        }

        String firstPlayer = getJoinedPlayerAt(minPlayer);
        return firstPlayer;
    }

    // bat dau luot moi hoan toan
    public void resetTurn() {
        isNewTurn = true;
        java.util.Arrays.fill(playerBypassedTurn, false);
        java.util.Arrays.fill(playerWithTurnPriority, false);
        chatChongList.clear();
        isHuongSaiTurn = false;
    }

//    public boolean checkEffect(String playerName, int effectType) {
//        if (playerName == null || effectList == null || effectList.size() == 0) {
//            return false;
//        }
//
//        boolean result = false;
//        for (int i = 0; i < effectList.size(); i++) {
//            SpecialEffect currEffect = (SpecialEffect) effectList.get(i);
//            if (currEffect.userName.equals(playerName) && currEffect.effectType == effectType) {
//                result = true;
//                if (effectType == EffectType.X2_BET) {
//                    effectList.remove(i);
//                }
//                break;
//            }
//
//        }
//
//        return result;
//    }

    public void monitorTurnTimeCheck(String userName, int addingTime) {
        if (userName == null) {
            return;
        }
        startTime = System.currentTimeMillis();
        stopTurnTimeCheck();
        timeoutTimer = new Timer();
        timeoutTimer.schedule(new removeTimeTurnMonitor(this, userName),
                (CardConstant.DEFAULT_TL_TABLE_TIMER + addingTime) * 1000);
//
//        VMSProtocolHandler.serviceTienLen.broadcastTableMessage(
//                    tableID, "",
//                    "bật timer");
//        log.info("Bat timer");
    }

    public void stopTurnTimeCheck() {
        if (timeoutTimer != null) {
            timeoutTimer.cancel();
            timeoutTimer = null;
        }
    }

    void clearJoinedPlayerList() {
        playerJoined.clear();
    }

    public String getJoinedPlayerAt(int index) {
        String retVal = null;
        try {
            if ((index >= 0) && (index < playerJoined.size())) {
                retVal = (String) playerJoined.get(index);
            }
        } catch (Exception ex) {
            log.error("getJoinedPlayerAt", ex);
        }
        return retVal;
    }

    class removeTimeTurnMonitor extends TimerTask {

        GameTable gt = null;
        String player = null;

        private removeTimeTurnMonitor(GameTable table, String turnPlayer) {
            super();

            this.gt = table;
            player = turnPlayer;
        }

        public void run() {
            stopTurnTimeCheck(); //Terminate the thread
            if (nextTurnPlayer >= playerJoined.size()) {
                return;
            }
            String userName = (String) playerJoined.get(nextTurnPlayer);
            if (!player.equals(userName)) {
                TienLenService.logGame.error("{}: TIMER ngat ko dung nguoi dung ({})",
                        gt.tableID, userName + " thay vi " + player);
                return;
            }
            IoSession session = PIServer.VMSProtocolHandler.getSessionByUserName(userName);
            // cap nhat la bai tu server cho client bi mat luot
//            VMSProtocolHandler.serviceTienLen.broadcastTableMessage(
//                    tableID, userName, userName+" bỏ lượt do quá giờ");
            TienLenService.logGame.debug("{}: {} bi qua gio", gt.tableID, userName);
            PIServer.VMSProtocolHandler.serviceTienLen.bypassMove(
                    session, tableType, tableID, userName, userName);
        }
    }

    // lay ten nguoi vua danh het bai trong luot gan nhat
    public String getLastFinishedPlayer() {
        for (int i = 0; i < playerJoined.size(); i++) {
            if (playerResult[i] == null) {
                if (i == 0) {
                    return null;
                } else {
                    return playerResult[i - 1];
                }
            }
        }
        return null;
    }

    // dem so nguoi con trong luot hien tai
    public int countTurnMembers() {
        int result = 0;
        for (byte c = 0; c < playerJoined.size(); c++) {
            if ((!playerBypassedTurn[c]) && (noCardsLeft[c] > 0)) {
                result++;
            }
        }
        return result;
    }
}
